from pydantic_settings import BaseSettings
from typing import List, Optional, Dict, Any
import yaml
import os
from pydantic import Field, field_validator

from app.core.cons import Cons

class PoolConfig(BaseSettings):
    """数据库连接池配置"""
    size: int = Field(..., description="连接池大小")
    max_overflow: int = Field(..., description="最大溢出连接数")
    timeout: int = Field(..., description="连接超时时间（秒）")
    recycle: int = Field(..., description="连接回收时间（秒）")

class DatabaseConfig(BaseSettings):
    """数据库配置"""
    user: str
    password: str
    host: str
    port: int
    database: str
    pool: PoolConfig
    
    @field_validator('password')
    def validate_password(cls, v):
        # 生产环境下不记录密码日志等安全措施
        return v

class LoggingConfig(BaseSettings):
    """日志配置"""
    level: str
    format: str
    file: Optional[str]

class ResponseConfig(BaseSettings):
    """响应配置"""
    truncate_length: int
    allowed_origins: List[str]

class SlowRequestConfig(BaseSettings):
    """慢请求配置"""
    threshold: float
    log_level: str

class InterceptorConfig(BaseSettings):
    """拦截器配置"""
    whitelist: List[str]
    response: ResponseConfig
    slow_request: SlowRequestConfig

class SwaggerConfig(BaseSettings):
    """Swagger配置"""
    title: str
    description: str

class AppConfig(BaseSettings):
    """应用配置"""
    name: str
    description: str
    version: str
    port: int

class Settings(BaseSettings):
    """应用配置类"""
    # 应用配置
    app: AppConfig
    
    # 数据库配置
    database: DatabaseConfig
    
    # 日志配置
    logging: LoggingConfig
    
    # 请求拦截器配置
    interceptor: InterceptorConfig
    
    # Swagger配置
    swagger: SwaggerConfig
    
    class Config:
        env_file = ".env"
        case_sensitive = False
    
    def get(self, path: str, default: Any = None):
        """通过点分隔的路径获取配置值
        
        Args:
            path: 点分隔的配置路径，如 'app.name', 'database.pool.size'
            default: 当路径不存在时返回的默认值
            
        Returns:
            配置值或默认值
        """
        keys = path.split('.')
        value = self
        
        try:
            for key in keys:
                # 尝试从Pydantic模型获取属性
                if hasattr(value, key):
                    value = getattr(value, key)
                # 尝试从字典获取键值
                elif isinstance(value, dict) and key in value:
                    value = value[key]
                else:
                    return default
            return value
        except Exception:
            return default
    
    # 保留几个常用的根级别的便捷访问属性
    @property
    def app_config(self):
        """应用配置"""
        return self.app
    
    @property
    def db_config(self):
        """数据库配置"""
        return self.database
    
    @property
    def log_config(self):
        """日志配置"""
        return self.logging
    
    @property
    def interceptor_config(self):
        """拦截器配置"""
        return self.interceptor
    
    @property
    def swagger_config(self):
        """Swagger配置"""
        return self.swagger
    
    def is_prod(self):
        """判断是否为生产环境
        
        Returns:
            bool: 如果是生产环境返回True，否则返回False
        """
        # 从环境变量获取当前环境
        current_env = get_activate_env()
        # 如果没有设置环境变量或者环境变量不是生产环境，则返回False
        if not current_env or current_env != 'prod':
            return False
        return True
    
    def is_dev(self):
        """判断是否为开发环境
        
        Returns:
            bool: 如果是开发环境返回True，否则返回False
        """
        current_env = get_activate_env()
        # 开发环境包括未指定环境和明确指定的dev环境
        if not current_env or current_env == 'dev':
            return True
        return False
    
    def is_test(self):
        """判断是否为测试环境
        
        Returns:
            bool: 如果是测试环境返回True，否则返回False
        """
        current_env = get_activate_env()
        return current_env == 'test' or current_env == 'alpha' or current_env == 'beta'
    
    def get_env(self):
        """获取当前环境名称
        
        Returns:
            str: 当前环境名称，未指定时返回'dev'
        """
        current_env = get_activate_env()
        return current_env or 'dev'
    
# 从YAML文件加载配置
def load_config_from_yaml(env: Optional[str] = None, config_path: str = None) -> Optional[Settings]:
    """从YAML文件加载配置，支持多环境配置文件
    
    Args:
        env: 环境名称，如 'dev', 'alpha', 'prod' 等
        config_path: 直接指定配置文件路径（优先级高于env）
        
    Returns:
        Settings实例或None
    """
    # 确定配置文件路径
    if config_path:
        file_path = config_path
    elif env:
        file_path = f"application-{env}.yml"
    else:
        file_path = "application.yml"
    
    try:
        # 检查文件是否存在
        if not os.path.exists(file_path):
            # 严格模式：指定的配置文件必须存在，不存在则直接报错
            error_msg = f"Error: Configuration file {file_path} not found"
            print(error_msg)
            raise FileNotFoundError(error_msg)
        with open(file_path, "r", encoding=Cons.UTF_8) as file:
            config_data = yaml.safe_load(file)
            if config_data:
                print(f"Loaded configuration from {file_path}")
                # 将嵌套字典转换为对应的配置类
                # 数据库连接池配置
                if isinstance(config_data.get('database', {}).get('pool'), dict):
                    config_data['database']['pool'] = PoolConfig(**config_data['database']['pool'])
                # 拦截器响应配置
                if isinstance(config_data.get('interceptor', {}).get('response'), dict):
                    config_data['interceptor']['response'] = ResponseConfig(**config_data['interceptor']['response'])
                # 拦截器慢请求配置
                if isinstance(config_data.get('interceptor', {}).get('slow_request'), dict):
                    config_data['interceptor']['slow_request'] = SlowRequestConfig(**config_data['interceptor']['slow_request'])
                return Settings(**config_data)
            return None
    except Exception as e:
        print(f"Error loading config from {file_path}: {e}")
        return None

# 获取环境变量中的activateEnv参数，如果没有则为None
def get_activate_env():
    """从环境变量获取activateEnv参数"""
    return os.environ.get("activateEnv")

# 延迟初始化全局设置实例
# 避免在导入时就加载配置，允许命令行参数影响配置加载
_settings: Optional[Settings] = None

def get_settings() -> Settings:
    """获取全局设置实例，确保只加载一次"""
    global _settings
    if _settings is None:
        _settings = load_config_from_yaml(env=get_activate_env())
        if _settings is None:
            raise RuntimeError("Failed to load configuration")
    return _settings

# 全局设置实例，使用时会自动初始化
settings = get_settings()
